package com.zlw.framework.beans;

import com.zlw.framework.web.mvc.Controller;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName BeanFactory
 * @Description TODO
 * @Author zhaoluowei
 * @Date 2020/1/28  23:19
 * @Version 1.0
 */

public class BeanFactory {
    //bean 类型到 bean的映射
    private static Map<Class<?>, Object> classToBean = new ConcurrentHashMap<>();

    public static Object getBean(Class<?> cls) {
        return classToBean.get(cls);
    }

    //bean 初始化的方法 参数是类定义
    public static void initBean(List<Class<?>> classList) throws Exception {
        List<Class<?>> toCreate = new ArrayList<>(classList);
        while (toCreate.size() != 0) {
            int remainSize = toCreate.size();
            for (int i = 0; i < toCreate.size(); i++) {
                //完成创建 就从容器中 删除
                if (finishCreate(toCreate.get(i))) {
                    toCreate.remove(i);
                }
            }

            if (toCreate.size() == remainSize) {
                throw new Exception("xian ru si xun huan");
            }

        }
    }

    private static boolean finishCreate(Class<?> cls) throws IllegalAccessException, InstantiationException {
        //判断 该类 是否 需要 初始化为 bean 如果 不需要直接返回true 从集合中删除
        //
        if (!cls.isAnnotationPresent(Bean.class) && !cls.isAnnotationPresent(Controller.class)) {
            return true;
        }

        //解决 类中 依赖的问题
        Object bean = cls.newInstance();
        for (Field field : cls.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)){
                Class<?> fieldType = field.getType();
                Object reliantBean = BeanFactory.getBean(fieldType);
                if (reliantBean==null){
                    return false;
                }
                field.setAccessible(true);
                field.set(bean,reliantBean);

            }
        }
        classToBean.put(cls,bean);
        return true;
    }

}
